// *******************************************************************
// >> File Name: /home/diabio/project/al_cache/al_cache/arc_cache/arc_lru_part.h
// >> Author: diabiolin
// >> Created Time: Fri 25 Apr 2025 09:20:44 PM CST
// >> Description:
// *******************************************************************

#pragma once 

#include "arc_cache_node.h"
#include <unordered_map>
// #include <mutex>

namespace al_cache{

template <typename Key, typename Value>
class ArcLruPart{
public:
	using NodeType = ArcNode<Key, Value>;
	using NodePtr = std::shared_ptr<NodeType>;
	using NodeMap = std::unordered_map<Key, NodePtr>;

	explicit ArcLruPart(size_t capacity, size_t transformThreshold)
		: capacity_(capacity)
		, ghostCapacity_(capacity)
		, transformThreshold_(transformThreshold)
		{
			initializeList();
		}

	bool put(Key key, Value value){
		if(capacity_ == 0){
			return false;
		}
		// std::lock_guard<std::mutex> lock(mutex_);
		auto it = mainCacheMap_.find(key);
		if(it != mainCacheMap_.end()){
			return updateExitingNode(it->second, value);
		}
		return addNewNode(key, value);
	}

	~ArcLruPart(){
		mainCacheMap_.clear();
		ghostCacheMap_.clear();

		if(mainHead_){
			mainHead_->next_ = nullptr;
		}
		if(mainTail_){
			mainTail_->prev_.reset();
		}
		mainHead_ = nullptr;
		mainTail_ = nullptr;

		if(ghostHead_){
			ghostHead_->next_ = nullptr;
		}
		if(ghostTail_){	
			ghostTail_->prev_.reset();
		}
		ghostHead_ = nullptr;
		ghostTail_ = nullptr;
	}

	bool get(Key key, Value& value, bool& shouldTransform){
		// std::lock_guard<std::mutex> lock(mutex_);
		auto it = mainCacheMap_.find(key);
		if(it != mainCacheMap_.end()){
			shouldTransform = updateNodeAccess(it->second);
			value = it->second->getValue();
			return true;
		}
		return false;
	}

	bool checkGhost(Key key){
		// std::lock_guard<std::mutex> lock(mutex_);
		auto it = ghostCacheMap_.find(key);
		if(it != ghostCacheMap_.end()){
			// 先断链
			NodePtr node = it->second;
			removeFromGhost(node);
			// 再 erase
			ghostCacheMap_.erase(it);
			// 之后不能再访问 it->second
			return true;
		}
		return false;
	}

	void increaseCapacity(){
		capacity_++;	
	}

	bool decreaseCapacity(){
		if(capacity_ <= 0){
			return false;
		}
		if(mainCacheMap_.size() == capacity_){
			evictLeastRecent();
		}
		capacity_--;
		return true;
	}


private:
	size_t capacity_;
	size_t ghostCapacity_;
	size_t transformThreshold_;
	// std::mutex mutex_;

	NodeMap mainCacheMap_;
	NodeMap ghostCacheMap_;

	NodePtr mainHead_;
	NodePtr mainTail_;

	NodePtr ghostHead_;
	NodePtr ghostTail_;

	// 一些私有方法
	void initializeList(){
		mainHead_ = std::make_shared<NodeType>();
		mainTail_ = std::make_shared<NodeType>();
		mainHead_->next_ = mainTail_;
		mainTail_->prev_ = mainHead_;

		ghostHead_ = std::make_shared<NodeType>();
		ghostTail_ = std::make_shared<NodeType>();
		ghostHead_->next_ = ghostTail_;
		ghostTail_->prev_ = ghostHead_;
	}

	bool updateExitingNode(NodePtr node, const Value& value){
		node->setValue(value);
		moveToFront(node);
		return true;
	}

	bool addNewNode(const Key& key, const Value& value){
		if(mainCacheMap_.size() >= capacity_){
			evictLeastRecent();
		}
		NodePtr newNode = std::make_shared<NodeType>(key, value);
		mainCacheMap_[key] = newNode;
		addToFront(newNode);
		return true;
	}

	bool updateNodeAccess(NodePtr node){
		moveToFront(node);
		node->incrementAccessCount();
		return node->getAccessCount() >= transformThreshold_;
	}

	void moveToFront(NodePtr node){
		if(auto prev = node->prev_.lock()){
			prev->next_ = node->next_;
		}
		if(node->next_){
			node->next_->prev_ = node->prev_;
		}
		// node->prev_->next_ = node->next_;
		// node->next_->prev_ = node->prev_;

		addToFront(node);
	}

	void addToFront(NodePtr node){
		node->next_ = mainHead_->next_;
		node->prev_ = mainHead_;
		if(node->next_){
			node->next_->prev_ = node;
		}
		mainHead_->next_ = node;
		// mainHead_->next_->prev_ = node;
		// mainHead_->next_ = node;
	}

	void evictLeastRecent(){
		NodePtr leastRecent = mainTail_->prev_.lock();
		if(leastRecent == mainHead_){
			return;
		}

		removeFromMain(leastRecent);

		if(ghostCacheMap_.size() >= ghostCapacity_){
			removeOldestGhost();
		}
		addToGhost(leastRecent);
		mainCacheMap_.erase(leastRecent->getKey());
	}

	void removeFromMain(NodePtr node){
		if(auto prev = node->prev_.lock()){
			prev->next_ = node->next_;
		}
		// node->prev_->next_ = node->next_;
		node->next_->prev_ = node->prev_;
	}

	void removeFromGhost(NodePtr node){
		if (!node) return;
		// 保存 prev/next，防止悬挂
		auto prev = node->prev_.lock();
		auto next = node->next_;
		if (prev) prev->next_ = next;
		if (next) next->prev_ = node->prev_;
		node->prev_.reset();
		node->next_ = nullptr;
	}

	void addToGhost(NodePtr node){
		node->accessCount_ = 1;
		
		node->next_ = ghostHead_->next_;
		node->prev_ = ghostHead_;
		if(node->next_){
			node->next_->prev_ = node;
		}
		// ghostHead_->next_->prev_ = node;
		ghostHead_->next_ = node;

		ghostCacheMap_[node->getKey()] = node;
	}

	void removeOldestGhost() {
		NodePtr oldestGhost = ghostTail_->prev_.lock();
		if (oldestGhost && oldestGhost != ghostHead_) {
			removeFromGhost(oldestGhost);
			ghostCacheMap_.erase(oldestGhost->getKey());
		}
	}
};

} // namespace al_cache 

